import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目分配结果封装类
 * 分析：这是在豆包上输入题目的结果，我是直接将题目输入进去得到的输出，逻辑有点问题，首先一点就是没有重复利用开发/产品人员，
 * 可能是需要突出强调每个人员可以投身两个项目。
 * 第二点存在的问题是在描述的产品人员数为N，项目数也为N，那么这两者数量应该是相等的。这里没有做为相等的进行处理，不过也
 * 并不影响总体逻辑，这里直接使用AI分析还是有局限性，不过代码整体逻辑上没有问题，且定义好整个算法的框架，是可以借鉴过来快速开发的。
 */
class AllocationResult {
    private final Map<String, ProjectAssignment> allocation;
    private final int totalCost;
    private final Map<String, Integer> developerLoad;
    private final Map<String, Integer> productLoad;

    public AllocationResult(Map<String, ProjectAssignment> allocation, int totalCost,
                            Map<String, Integer> developerLoad, Map<String, Integer> productLoad) {
        this.allocation = allocation;
        this.totalCost = totalCost;
        this.developerLoad = developerLoad;
        this.productLoad = productLoad;
    }

    public Map<String, ProjectAssignment> getAllocation() { return allocation; }
    public int getTotalCost() { return totalCost; }
    public Map<String, Integer> getDeveloperLoad() { return developerLoad; }
    public Map<String, Integer> getProductLoad() { return productLoad; }
}

/**
 * 单个项目的分配详情
 */
class ProjectAssignment {
    private final String developer;
    private final int developerSkill;
    private final String product;
    private final int productSkill;
    private final int difficulty;

    public ProjectAssignment(String developer, int developerSkill, String product,
                             int productSkill, int difficulty) {
        this.developer = developer;
        this.developerSkill = developerSkill;
        this.product = product;
        this.productSkill = productSkill;
        this.difficulty = difficulty;
    }

    public String getDeveloper() { return developer; }
    public int getDeveloperSkill() { return developerSkill; }
    public String getProduct() { return product; }
    public int getProductSkill() { return productSkill; }
    public int getDifficulty() { return difficulty; }
}

/**
 * 项目分配主类
 */
public class ProjectAllocator {

    /**
     * 计算最优项目分配方案
     * @param developerSkills 开发人员技能映射
     * @param productSkills 产品人员技能映射
     * @param projectDifficulties 项目难度映射
     * @return 分配结果，若无法满足所有项目则返回null
     */
    public static AllocationResult allocateProjects(
            Map<String, Integer> developerSkills,
            Map<String, Integer> productSkills,
            Map<String, Integer> projectDifficulties) {

        // 初始化开发人员项目计数
        Map<String, Integer> devProjectCount = new HashMap<>();
        developerSkills.keySet().forEach(dev -> devProjectCount.put(dev, 0));

        // 初始化产品人员项目计数
        Map<String, Integer> prodProjectCount = new HashMap<>();
        productSkills.keySet().forEach(prod -> prodProjectCount.put(prod, 0));

        // 按项目难度从高到低排序
        List<Map.Entry<String, Integer>> sortedProjects = new ArrayList<>(projectDifficulties.entrySet());
        sortedProjects.sort((a, b) -> Integer.compare(b.getValue(), a.getValue()));

        // 存储分配结果
        Map<String, ProjectAssignment> allocation = new HashMap<>();
        int totalCost = 0;

        for (Map.Entry<String, Integer> project : sortedProjects) {
            String projectName = project.getKey();
            int difficulty = project.getValue();

            // 筛选符合条件的开发人员
            List<Map.Entry<String, Integer>> eligibleDevs = developerSkills.entrySet().stream()
                    .filter(entry -> entry.getValue() >= difficulty
                            && devProjectCount.get(entry.getKey()) < 2)
                    .sorted((a, b) -> {
                        // 先按项目数量排序，再按技能等级排序
                        int countCompare = Integer.compare(
                                devProjectCount.get(a.getKey()),
                                devProjectCount.get(b.getKey())
                        );
                        return countCompare != 0 ? countCompare
                                : Integer.compare(a.getValue(), b.getValue());
                    })
                    .collect(Collectors.toList());

            // 筛选符合条件的产品人员
            List<Map.Entry<String, Integer>> eligibleProds = productSkills.entrySet().stream()
                    .filter(entry -> entry.getValue() >= difficulty
                            && prodProjectCount.get(entry.getKey()) < 2)
                    .sorted((a, b) -> {
                        // 先按项目数量排序，再按技能等级排序
                        int countCompare = Integer.compare(
                                prodProjectCount.get(a.getKey()),
                                prodProjectCount.get(b.getKey())
                        );
                        return countCompare != 0 ? countCompare
                                : Integer.compare(a.getValue(), b.getValue());
                    })
                    .collect(Collectors.toList());

            // 检查是否有合适的人员
            if (eligibleDevs.isEmpty() || eligibleProds.isEmpty()) {
                return null;
            }

            // 选择最合适的开发和产品人员
            Map.Entry<String, Integer> selectedDev = eligibleDevs.get(0);
            Map.Entry<String, Integer> selectedProd = eligibleProds.get(0);

            // 更新项目计数
            devProjectCount.put(selectedDev.getKey(), devProjectCount.get(selectedDev.getKey()) + 1);
            prodProjectCount.put(selectedProd.getKey(), prodProjectCount.get(selectedProd.getKey()) + 1);

            // 累计总成本
            totalCost += selectedDev.getValue() + selectedProd.getValue();

            // 记录分配结果
            allocation.put(projectName, new ProjectAssignment(
                    selectedDev.getKey(),
                    selectedDev.getValue(),
                    selectedProd.getKey(),
                    selectedProd.getValue(),
                    difficulty
            ));
        }

        return new AllocationResult(allocation, totalCost,
                new HashMap<>(devProjectCount), new HashMap<>(prodProjectCount));
    }

    public static void main(String[] args) {
        // 示例数据
        Map<String, Integer> developerSkills = new HashMap<>();
        developerSkills.put("A", 1);
        developerSkills.put("B", 2);
        developerSkills.put("C", 3);
        developerSkills.put("D", 2);
        developerSkills.put("E", 4);
        developerSkills.put("F", 3);

        Map<String, Integer> productSkills = new HashMap<>();
        productSkills.put("a", 1);
        productSkills.put("b", 2);
        productSkills.put("c", 3);
        productSkills.put("d", 2);
        productSkills.put("e", 4);

        Map<String, Integer> projectDifficulties = new HashMap<>();
        projectDifficulties.put("project1", 1);
        projectDifficulties.put("project2", 2);
        projectDifficulties.put("project3", 3);
        projectDifficulties.put("project4", 2);

        // 获取分配结果
        AllocationResult result = allocateProjects(developerSkills, productSkills, projectDifficulties);

        if (result == null) {
            System.out.println("无法找到满足所有条件的分配方案");
        } else {
            System.out.println("总技能等级之和（总费用）: " + result.getTotalCost() + "\n");
            System.out.println("项目分配方案:");

            // 遍历输出分配结果
            result.getAllocation().forEach((project, details) -> {
                System.out.println(project + " (难度 " + details.getDifficulty() + "):");
                System.out.println("  开发人员: " + details.getDeveloper() +
                        " (技能 " + details.getDeveloperSkill() + ")");
                System.out.println("  产品人员: " + details.getProduct() +
                        " (技能 " + details.getProductSkill() + ")\n");
            });

            System.out.println("人员负载情况:");
            System.out.println("开发人员负责项目数: " + result.getDeveloperLoad());
            System.out.println("产品人员负责项目数: " + result.getProductLoad());
        }
    }
}
    